<template>
    <div class="otp-input-container" :class="{ 'is-error': hasError }">
        <div class="otp-input-explanation" v-if="showExplanation">
            <slot name="explanation">
                <p>请输入您的身份验证器应用生成的6位验证码</p>
            </slot>
        </div>

        <div class="otp-input-wrapper">
            <div v-for="(digit, index) in length" :key="index" class="otp-digit-container"
                :class="{ 'is-filled': value.length > index, 'is-active': activeIndex === index }" @click="focusInput">
                <span class="otp-digit">{{ value[index] || '' }}</span>
            </div>
        </div>

        <div class="otp-error-message" v-if="errorMessage">
            <i class="el-icon-warning"></i> {{ errorMessage }}
        </div>

        <input ref="hiddenInput" type="tel" :maxlength="length" v-model="value" class="otp-hidden-input"
            @focus="activeIndex = value.length" @blur="activeIndex = -1" @input="handleInput" @keydown="handleKeyDown"
            @paste="handlePaste" autocomplete="one-time-code" />
    </div>
</template>

<script>
export default {
    name: 'OtpInput',
    props: {
        initialValue: {
            type: String,
            default: ''
        },
        length: {
            type: Number,
            default: 6
        },
        autoSubmit: {
            type: Boolean,
            default: true
        },
        hasError: {
            type: Boolean,
            default: false
        },
        errorMessage: {
            type: String,
            default: ''
        },
        showExplanation: {
            type: Boolean,
            default: true
        }
    },
    data() {
        return {
            value: this.initialValue,
            activeIndex: -1
        }
    },
    watch: {
        initialValue(newVal) {
            this.value = newVal;
        }
    },
    mounted() {
        // 自动聚焦到输入框
        this.focusInput();
    },
    methods: {
        focusInput() {
            this.$refs.hiddenInput.focus();
        },
        handleInput() {
            // 只允许数字
            this.value = this.value.replace(/[^0-9]/g, '');
            this.activeIndex = this.value.length;

            // 发出input事件
            this.$emit('input', this.value);

            // 如果输入完成且启用了自动提交，则触发完成事件
            if (this.value.length === this.length && this.autoSubmit) {
                this.$emit('complete', this.value);
            }
        },
        handleKeyDown(e) {
            // 如果按下删除键且值为空，发出back事件
            if (e.key === 'Backspace' && this.value.length === 0) {
                this.$emit('back');
            }
        },
        handlePaste(e) {
            e.preventDefault();
            const pasteData = e.clipboardData.getData('text/plain').trim();

            // 只保留数字并限制长度
            const numericData = pasteData.replace(/[^0-9]/g, '').substring(0, this.length);

            if (numericData) {
                this.value = numericData;
                this.handleInput();
            }
        },
        reset() {
            this.value = '';
            this.activeIndex = -1;
        },
        focus() {
            this.focusInput();
        }
    }
}
</script>

<style lang="scss" scoped>
.otp-input-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;

    &.is-error {
        .otp-digit-container {
            border-color: #f56c6c;
            animation: shake 0.5s cubic-bezier(.36, .07, .19, .97) both;
        }
    }
}

.otp-input-explanation {
    margin-bottom: 16px;
    text-align: center;
    color: var(--text-secondary, #606266);
    font-size: 14px;
    line-height: 1.5;
}

.otp-input-wrapper {
    display: flex;
    justify-content: center;
    gap: 12px;
    margin-bottom: 16px;

    @media (max-width: 480px) {
        gap: 8px;
    }
}

.otp-digit-container {
    width: 50px;
    height: 50px;
    border-radius: 50%;
    border: 2px solid var(--border-color, #dcdfe6);
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--bg-color, #f5f7fa);
    transition: all 0.3s ease;
    position: relative;

    @media (max-width: 480px) {
        width: 40px;
        height: 40px;
    }

    &.is-filled {
        border-color: var(--primary-color, #409eff);
        background-color: var(--bg-filled, #ecf5ff);
    }

    &.is-active {
        border-color: var(--primary-color, #409eff);
        box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);

        &::after {
            content: '';
            position: absolute;
            bottom: 8px;
            width: 8px;
            height: 8px;
            background-color: var(--primary-color, #409eff);
            border-radius: 50%;
            animation: blink 1s infinite;
        }
    }
}

.otp-digit {
    font-size: 20px;
    font-weight: 600;
    color: var(--text-primary, #303133);

    @media (max-width: 480px) {
        font-size: 18px;
    }
}

.otp-hidden-input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    pointer-events: none;
}

.otp-error-message {
    color: #f56c6c;
    font-size: 12px;
    margin-top: 8px;
    display: flex;
    align-items: center;
    gap: 4px;
}

@keyframes blink {

    0%,
    100% {
        opacity: 0;
    }

    50% {
        opacity: 1;
    }
}

@keyframes shake {

    10%,
    90% {
        transform: translateX(-1px);
    }

    20%,
    80% {
        transform: translateX(2px);
    }

    30%,
    50%,
    70% {
        transform: translateX(-3px);
    }

    40%,
    60% {
        transform: translateX(3px);
    }
}

// 黑夜模式适配
@media (prefers-color-scheme: dark) {
    .otp-digit-container {
        background-color: var(--bg-color-dark, #1a1a1a);
        border-color: var(--border-color-dark, #4c4c4c);
    }

    .otp-digit {
        color: var(--text-primary-dark, #e0e0e0);
    }

    .otp-input-explanation {
        color: var(--text-secondary-dark, #a0a0a0);
    }
}

// 暗色模式样式
.dark-mode {
    .otp-digit-container {
        background-color: var(--bg-color-dark, #1a1a1a);
        border-color: var(--border-color-dark, #4c4c4c);

        &.is-filled {
            border-color: var(--primary-color, #409eff);
            background-color: rgba(64, 158, 255, 0.1);
        }
    }

    .otp-digit {
        color: var(--text-primary-dark, #e0e0e0);
    }

    .otp-input-explanation {
        color: var(--text-secondary-dark, #a0a0a0);
    }
}
</style>